#include <stdint.h>
#include <stdio.h>
#include "stm32f1xx_hal.h"
#include "stepper_ctrl.h"
#include "stepper_param.h"

extern TIM_HandleTypeDef htim3;
extern TIM_HandleTypeDef htim4;

typedef struct {
    TIM_HandleTypeDef *pwm_htim;
    uint8_t pwm_htim_channel;
    TIM_HandleTypeDef *cnt_pwm_htim;
    GPIO_TypeDef *pul_port;
    uint16_t pul_pin;
    GPIO_TypeDef *dir_port;
    uint16_t dir_pin;
    bool dir_reverse;
    GPIO_TypeDef *en_port;
    uint16_t en_pin;
}stepper_ctrl_t;

static stepper_ctrl_t stepper[STEPPER_NUM] = 
{
	{ /* STEPPER_X_INDEX */
    .pwm_htim = &htim3,
    .pwm_htim_channel = TIM_CHANNEL_1,
    .cnt_pwm_htim = &htim4,
    .pul_port = GPIOA,
    .pul_pin = GPIO_PIN_6,
    .dir_port = GPIOB,
    .dir_pin = GPIO_PIN_7,
    .dir_reverse = 0, 
    .en_port = GPIOC,
    .en_pin = GPIO_PIN_8,
	},
	{ /* STEPPER_Y_INDEX */
    .pwm_htim = &htim3,
    .pwm_htim_channel = TIM_CHANNEL_1,
    .cnt_pwm_htim = &htim4,
    .pul_port = GPIOA,
    .pul_pin = GPIO_PIN_6,
    .dir_port = GPIOB,
    .dir_pin = GPIO_PIN_7,
    .dir_reverse = 0,
    .en_port = GPIOC,
    .en_pin = GPIO_PIN_8,
	},
	{ /* STEPPER_Z_INDEX */
    .pwm_htim = &htim3,
    .pwm_htim_channel = TIM_CHANNEL_1,
    .cnt_pwm_htim = &htim4,
    .pul_port = GPIOA,
    .pul_pin = GPIO_PIN_6,
    .dir_port = GPIOB,
    .dir_pin = GPIO_PIN_7,
    .dir_reverse = 0,
    .en_port = GPIOC,
    .en_pin = GPIO_PIN_8,
	}
};

/**
 * @brief stepper control
 * @param stepper_index
 * 		@arg STEPPER_INDEX_X
 * 		@arg STEPPER_INDEX_Y
 * 		@arg STEPPER_INDEX_Z
 * @param dir
 * 		@arg STEPPER_DIR_CLKWISE
 * 		@arg STEPPER_DIR_ANTICLKWISE
 * @param en
 * 		@arg STEPPER_EN_ENABLE
 * 		@arg STEPPER_EN_DISABLE 
 * @param state
 * 		@arg STEPPER_STATE_STOP
 * 		@arg STEPPER_STATE_RUN
 */
void stepper_dir(uint8_t stepper_index, uint8_t dir)
{
    HAL_GPIO_WritePin(stepper[stepper_index].dir_port, 
            stepper[stepper_index].dir_pin, dir ^ stepper[stepper_index].dir_reverse);
}

void stepper_en(uint8_t stepper_index, uint8_t en)
{
    HAL_GPIO_WritePin(stepper[stepper_index].en_port, 
            stepper[stepper_index].en_pin, en);
}

void stepper_pwm_state(uint8_t stepper_index, uint8_t state)
{
    if (state == STEPPER_STATE_RUN) {
        HAL_TIM_PWM_Start(stepper[stepper_index].pwm_htim, 
                stepper[stepper_index].pwm_htim_channel);
    }
    else if (state == STEPPER_STATE_STOP) {
        HAL_TIM_PWM_Stop(stepper[stepper_index].pwm_htim, 
                stepper[stepper_index].pwm_htim_channel);
    }
}

/**
 * @brief 设置 ARR 来控制 pwm 脉冲频率
 */
void stepper_pwm_freq_byARR(uint8_t stepper_index, uint16_t ARR_val)
{
    __HAL_TIM_SetAutoreload(stepper[stepper_index].pwm_htim, ARR_val);
    __HAL_TIM_SetCounter(stepper[stepper_index].pwm_htim, 0);
    __HAL_TIM_SetCompare(stepper[stepper_index].pwm_htim, 
            stepper[stepper_index].pwm_htim_channel, ARR_val/2);
}

/**
 * @brief 设置转动步数即脉冲数
 * @note 应该有更新中断回调函数 HAL_TIM_PeriodElapsedCallback ，
 *       其中根据需要可以添加，关闭 pwm 输出、关闭更新中断等
 */
void stepper_make_steps(uint8_t stepper_index, uint32_t step_num)
{
    HAL_TIM_Base_Stop_IT(stepper[stepper_index].cnt_pwm_htim);
    __HAL_TIM_CLEAR_FLAG(stepper[STEPPER_X_INDEX].cnt_pwm_htim, TIM_FLAG_UPDATE);
    __HAL_TIM_SetAutoreload(stepper[stepper_index].cnt_pwm_htim, step_num);
    __HAL_TIM_SetCounter(stepper[stepper_index].cnt_pwm_htim, 0);
    HAL_TIM_Base_Start_IT(stepper[stepper_index].cnt_pwm_htim); 
}

/**
 * @brief 获取在一次控制中已经行走步数即脉冲数
 * @note 主要用于意外中断停车
 */
void stepper_get_steps(uint8_t stepper_index, uint32_t *step_num)
{
    *step_num = __HAL_TIM_GetCounter(stepper[stepper_index].cnt_pwm_htim);
}

/* 存放 XYZ 步进电机的位移量 */
static float stepper_x_position, stepper_y_position, stepper_z_position; 

/**
 * @brief 坐标处理回调者，stepper_ctrl 层不做坐标处理记录，所以添加了回调，由 move 层提供回调函数，并处理记录坐标
 * @note posCallBack 回调函数需要初始
 */

posCallBack x_position_callback, y_position_callback, z_position_callback;

void x_position_result_caller() 
{
    x_position_callback(stepper_x_position);
    stepper_x_position = 0;
}
void y_position_result_caller() 
{
    y_position_callback(stepper_y_position);
    stepper_y_position = 0;
}
void z_position_result_caller() 
{
    z_position_callback(stepper_z_position);
    stepper_z_position = 0;
}

/**
 * @brief PWM 的从计数器的中断回调函数
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim==(stepper[STEPPER_X_INDEX].cnt_pwm_htim)) {
        //HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9);
        HAL_TIM_PWM_Stop(stepper[STEPPER_X_INDEX].pwm_htim, stepper[STEPPER_X_INDEX].pwm_htim_channel);
        __HAL_TIM_CLEAR_FLAG(stepper[STEPPER_X_INDEX].cnt_pwm_htim, TIM_FLAG_UPDATE);
        stepper_x_position += (stp_x_param.distance_pul * __HAL_TIM_GetAutoreload(stepper[STEPPER_X_INDEX].cnt_pwm_htim));
        printf("x_position:%f\n", stepper_x_position); /* 完成该次位移变化记录 */
        x_position_result_caller();
    }
}
